package com.xyy.saas.payment.adpater.impl;

import com.alibaba.fastjson.JSON;
import  com.alibaba.fastjson.JSONObject;
import com.xyy.saas.payment.adpater.PaymentAdapter;
import com.xyy.saas.payment.adpater.assemble.FBankRequestParamAssemble;
import com.xyy.saas.payment.adpater.assemble.dto.WithdrawAccountDto;
import com.xyy.saas.payment.adpater.fumin.pojo.domain.SeparateAccountDO;
import com.xyy.saas.payment.adpater.yop.*;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.enums.PictureEnum;
import com.xyy.saas.payment.common.enums.YopProductInfoEnum;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.bo.*;
import com.xyy.saas.payment.cores.enums.*;
import com.xyy.saas.payment.cores.param.Pair;
import com.xyy.saas.payment.cores.vo.ContactInfo;
import com.xyy.saas.payment.cores.vo.OperatorInfo;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.dao.model.ThirdUserInfo;
import com.xyy.saas.payment.merchant.core.dto.*;
import com.xyy.saas.payment.merchant.core.vo.*;
import com.xyy.saas.payment.payment.core.bo.RefundBO;
import com.xyy.saas.payment.payment.core.bo.WithdrawalBO;
import com.xyy.saas.payment.payment.core.dto.*;
import com.xyy.saas.payment.payment.core.service.PrePayOrderService;
import com.xyy.saas.payment.payment.core.service.RefundOrderService;
import com.xyy.saas.payment.service.ThirdUserInfoService;
import com.xyy.saas.payment.service.UserService;
import com.xyy.saas.payment.util.*;
import com.yeepay.yop.sdk.service.account.model.*;
import com.yeepay.yop.sdk.service.account.request.*;
import com.yeepay.yop.sdk.service.aggpay.model.PrePayOrderResponseDTOResult;
import com.yeepay.yop.sdk.service.aggpay.request.PrePayRequest;
import com.yeepay.yop.sdk.service.mer.model.RegisterContributeMerchantV2ContributeMerchantNetInRespDtoResult;
import com.yeepay.yop.sdk.service.mer.model.RegisterContributeMicroV2ContributeMicroMerchantNetInRespDtoResult;
import com.yeepay.yop.sdk.service.mer.request.RegisterContributeMerchantV2Request;
import com.yeepay.yop.sdk.service.mer.request.RegisterContributeMicroV2Request;
import com.yeepay.yop.sdk.service.trade.model.RefundQueryQueryRefundResponseDTOResult;
import com.yeepay.yop.sdk.service.trade.model.RefundResponseRefundDTOResult;
import com.yeepay.yop.sdk.service.trade.request.RefundQueryRequest;
import com.yeepay.yop.sdk.service.trade.request.RefundRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * 易宝支付
 */
@Service
@Slf4j
public class YopAdapter implements PaymentAdapter {
    @Resource
    private PrePayOrderService prePayOrderService;
    @Resource
    private YopWithdraw yopWithdraw;
    @Resource
    private YopCreateMerchant yopCreateMerchant;
    @Resource
    private YopCreatePersonal yopCreatePersonal;
    @Resource
    private YopCardBind yopCardBind;
    @Resource
    private YopCardUnBind yopCardUnBind;
    @Resource
    private YopBalanceQuery yopBalanceQuery;
    @Resource
    private YopBalanceQueryV2 yopBalanceQueryV2;
    @Resource
    private YopRefund yopRefund;
    @Resource
    private YopRefundQuery yopRefundQuery;
    @Resource
    private YopPay yopPay;
    @Resource
    private YopTransfer yopTransfer;
    @Resource
    private YopTransferQuery yopTransferQuery;
    @Resource
    private YopFileUpload yopFileUpload;
    @Resource
    private FBankRequestParamAssemble paramAssemble;
    @Resource
    private UserService userService;
    @Resource
    private ThirdUserInfoService thirdUserInfoService;
    @Resource
    private RefundOrderService refundOrderService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private LeafUtil leafUtil;

    /**
     * 创建预支付单
     */
    @Override
    public PrepayBo prepay(PrepayDto prepayDto) throws PaymentException {
        return prePayOrderService.prepayOrderByPrepayDto(prepayDto);
    }

    /**
     * 提现申请
     */
    @Override
    public WithdrawalBO withdraw(WithdrawalDto withdrawalDto) throws PaymentException {
        log.info("YopAdapter#withdraw withdrawalDto={}", JSONUtils.toJSON(withdrawalDto));

        // 1.组装请求参数
        WithdrawAccountDto withdrawAccountDto = paramAssemble.getWithdrawAccountInfo(withdrawalDto.getUserId());
        WithdrawOrderRequest requestParam = new WithdrawOrderRequest();
        requestParam.setParentMerchantNo(ApolloUtil.getProperty("yop.merchantNo"));
        requestParam.setRequestNo(withdrawalDto.getWithdrawalNo());
        requestParam.setMerchantNo(withdrawAccountDto.getPayerAccountNo());
        requestParam.setBankAccountNo(withdrawAccountDto.getPayeeAccountNo());
        requestParam.setReceiveType("REAL_TIME");
        requestParam.setOrderAmount(AmountCastUtil.castFen2YuanByBigDecimal(withdrawalDto.getAmount()));
        requestParam.setNotifyUrl(ApolloUtil.getProperty("yop.callBack.withdrawal"));

        // 2.发送请求
        WithdrawOrderWithdrawOrderRespDTOResult result = yopWithdraw.withdraw(requestParam);

        // 3.响应
        WithdrawalBO withdrawalBO = new WithdrawalBO();
        withdrawalBO.setChannelWithdrawNo(result.getOrderNo());
        withdrawalBO.setUserName(withdrawAccountDto.getPayeeName());
        withdrawalBO.setStatus(result.getStatus());
        withdrawalBO.setWithdrawalNo(withdrawalDto.getWithdrawalNo());
        return withdrawalBO;
    }

    /**
     * @
     */
    @Override
    public UserPicBo uploadPic(UserDto userDto) throws PaymentException {
        UserPicBo userPicBo = new UserPicBo();
        userPicBo.setAccountNo(userDto.getAccNo());
        userPicBo.setUser(userDto.getUserId());
        userPicBo.setThirdType(Constants.YOP);
        userPicBo.setType(userDto.getAccountType());
        return userPicBo;
    }

    /**
     * 企业开户
     */
    @Override
    public SubAppBo createMerchant(UserDto userDto) throws PaymentException {
        log.info("YopAdapter#createMerchant userDto={}", JSONUtils.toJSON(userDto));

        // 0.参数校验
        userDto.checkYopMerchantParam();

        // 1.组装参数
        RegisterContributeMerchantV2Request requestParam = new RegisterContributeMerchantV2Request();

        // 基础信息
        requestParam.setRequestNo(userDto.getUserId() + "_" + leafUtil.getSnowflakeId());
        requestParam.setBusinessRole("SETTLED_MERCHANT");

        // 企业信息
        JSONObject subjectInfo = new JSONObject();
        IdentityInfo identityInfo = userDto.getIdentityInfo();
        subjectInfo.put("signType", userDto.getMerchantCategory());
        subjectInfo.put("licenceNo", identityInfo.getId());
        subjectInfo.put("licenceUrl", uploadPicture(userDto.getPicMap().
                get(String.valueOf(PictureEnum.BUSINESS_CERT_PIC.getCode())), userDto.getUserId()));
        subjectInfo.put("signName", userDto.getName());
        subjectInfo.put("shortName", userDto.getName());
        subjectInfo.put("openAccountLicenceNo", identityInfo.getOpenAccountLicenceNo());
        subjectInfo.put("openAccountLicenceUrl", uploadPicture(userDto.getPicMap().
                get(String.valueOf(PictureEnum.OPEN_ACCOUNT_PIC.getCode())), userDto.getUserId()));
        requestParam.setMerchantSubjectInfo(subjectInfo.toJSONString());

        // 法人信息
        JSONObject corporationInfo = new JSONObject();
        ContactInfo corporation = userDto.getContactInfos().get(NumberUtils.INTEGER_ZERO);
        corporationInfo.put("legalName", corporation.getContactName());
        corporationInfo.put("legalLicenceType", "ID_CARD");
        corporationInfo.put("legalLicenceNo", corporation.getContactCertNo());
        corporationInfo.put("legalLicenceFrontUrl", uploadPicture(userDto.getPicMap().
                get(String.valueOf(PictureEnum.LEGAL_CERT_FRONT.getCode())), userDto.getUserId()));
        corporationInfo.put("legalLicenceBackUrl", uploadPicture(userDto.getPicMap().
                get(String.valueOf(PictureEnum.LEGAL_CERT_BACK.getCode())), userDto.getUserId()));
        requestParam.setMerchantCorporationInfo(corporationInfo.toJSONString());

        // 联系人信息
        JSONObject contactInfo = new JSONObject();
        OperatorInfo operatorInfo = userDto.getOperatorInfo();
        contactInfo.put("contactName", operatorInfo.getName());
        contactInfo.put("contactMobile", operatorInfo.getPhone());
        contactInfo.put("contactEmail", operatorInfo.getEmail());
        contactInfo.put("servicePhone", operatorInfo.getPhone());
        requestParam.setMerchantContactInfo(contactInfo.toJSONString());

        // 经营地址
        JSONObject businessAddressInfo = new JSONObject();
        businessAddressInfo.put("province", identityInfo.getBusinessProvince());
        businessAddressInfo.put("city", identityInfo.getBusinessCity());
        businessAddressInfo.put("district", identityInfo.getBusinessDistrict());
        businessAddressInfo.put("address", identityInfo.getBusinessAddress());
        requestParam.setBusinessAddressInfo(businessAddressInfo.toJSONString());

        // 结算账户
        JSONObject settlementAccountInfo = new JSONObject();
        Recipient recipient = userDto.getSettleAccountDto().getRecipient();
        settlementAccountInfo.put("settlementDirection", "ACCOUNT");
        settlementAccountInfo.put("bankAccountType", recipient.getCardType());
        settlementAccountInfo.put("bankCardNo", recipient.getAccount());
        settlementAccountInfo.put("bankCode", recipient.getOpenBankCode());
        requestParam.setSettlementAccountInfo(settlementAccountInfo.toJSONString());

        // 产品信息
//        requestParam.setProductInfo(YopProductInfoEnum.getProductList(userDto.getAccountType()));

        // 回调地址
        requestParam.setNotifyUrl(ApolloUtil.getProperty("yop.callBack.openAccount"));

        // 2.发送请求
        RegisterContributeMerchantV2ContributeMerchantNetInRespDtoResult result = yopCreateMerchant.createMerchant(requestParam);

        // 3.保存商户号
        userService.updateThirdUserIdByUserId(userDto.getUserId(), Constants.YOP, result.getMerchantNo());
        userDto.setAccNo(result.getMerchantNo());

        // 5.构建响应参数
        SubAppBo subAppBo = new SubAppBo();
        subAppBo.setState(UserApplyStateEnum.SUCCEEDED);
        subAppBo.setAccountNo(result.getMerchantNo());
        subAppBo.setThirdType(Constants.YOP);
        return subAppBo;
    }

    /**
     * 个人开户
     */
    @Override
    public SubAppBo createPersonal(UserDto userDto) throws PaymentException {
        log.info("YopAdapter#createPersonal userDto={}", JSONUtils.toJSON(userDto));

        // 0.参数校验
        userDto.checkYopPersonalParam();

        // 1.组装参数
        RegisterContributeMicroV2Request requestParam = new RegisterContributeMicroV2Request();

        // 基础信息
        requestParam.setRequestNo(userDto.getUserId() + "_" + leafUtil.getSnowflakeId());
        requestParam.setBusinessRole("SETTLED_MERCHANT");

        // 商户信息
        JSONObject subjectInfo = new JSONObject();
        subjectInfo.put("signName", userDto.getName());
        subjectInfo.put("shortName", userDto.getName());
        requestParam.setMerchantSubjectInfo(subjectInfo.toJSONString());

        // 个人信息
        JSONObject corporationInfo = new JSONObject();
        IdentityInfo identityInfo = userDto.getIdentityInfo();
        corporationInfo.put("legalLicenceType", "ID_CARD");
        corporationInfo.put("legalLicenceNo", identityInfo.getId());
        corporationInfo.put("legalLicenceFrontUrl", uploadPicture(userDto.getPicMap().
                get(String.valueOf(PictureEnum.PERSONAL_CERT_FRONT.getCode())), userDto.getUserId()));
        corporationInfo.put("legalLicenceBackUrl", uploadPicture(userDto.getPicMap().
                get(String.valueOf(PictureEnum.PERSONAL_CERT_BACK.getCode())), userDto.getUserId()));
        corporationInfo.put("mobile", userDto.getMobile());
        requestParam.setMerchantCorporationInfo(corporationInfo.toJSONString());

        // 经营地址
        JSONObject businessAddressInfo = new JSONObject();
        businessAddressInfo.put("province", identityInfo.getBusinessProvince());
        businessAddressInfo.put("city", identityInfo.getBusinessCity());
        businessAddressInfo.put("district", identityInfo.getBusinessDistrict());
        businessAddressInfo.put("address", identityInfo.getBusinessAddress());
        requestParam.setBusinessAddressInfo(businessAddressInfo.toJSONString());

        // 账户信息
        JSONObject accountInfo = new JSONObject();
        Recipient recipient = userDto.getSettleAccountDto().getRecipient();
        accountInfo.put("settlementDirection", "ACCOUNT");
        accountInfo.put("bankAccountType", "DEBIT_CARD");
        accountInfo.put("bankCardNo", recipient.getAccount());
        accountInfo.put("bankCode", recipient.getOpenBankCode());
        requestParam.setAccountInfo(accountInfo.toJSONString());

        // 产品信息
//        requestParam.setProductInfo(YopProductInfoEnum.getProductList(userDto.getAccountType()));

        // 回调地址
        requestParam.setNotifyUrl(ApolloUtil.getProperty("yop.callBack.openAccount"));

        // 2.发送请求
        RegisterContributeMicroV2ContributeMicroMerchantNetInRespDtoResult result = yopCreatePersonal.createPersonal(requestParam);

        // 3.保存商户号
        userService.updateThirdUserIdByUserId(userDto.getUserId(), Constants.YOP, result.getMerchantNo());
        userDto.setAccNo(result.getMerchantNo());

        // 5.构建响应参数
        SubAppBo subAppBo = new SubAppBo();
        subAppBo.setState(UserApplyStateEnum.SUCCEEDED);
        subAppBo.setAccountNo(result.getMerchantNo());
        subAppBo.setThirdType(Constants.YOP);
        return subAppBo;
    }

    /**
     * 企业绑卡
     */
    @Override
    public String merchantCardBind(MerchantCardBindDto merchantCardBindDto) throws PaymentException {
        log.info("YopAdapter#merchantCardBind merchantCardBindDto={}", JSONUtils.toJSON(merchantCardBindDto));

        // 0.参数校验
        merchantCardBindDto.checkParam();

        // 1.组装参数
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(merchantCardBindDto.getUserId());

        if(thirdUserInfo == null) {
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST);
        }

        WithdrawCardBindRequest requestParam = new WithdrawCardBindRequest();
        requestParam.setMerchantNo(thirdUserInfo.getThirdUserId());
        requestParam.setBankCardType(merchantCardBindDto.getCardType());
        requestParam.setAccountNo(merchantCardBindDto.getAccount());
        requestParam.setBankCode(merchantCardBindDto.getOpenBankCode());
        requestParam.setBranchCode(merchantCardBindDto.getBranchBankCd());

        // 2.发送请求
        yopCardBind.cardBind(requestParam);

        return "";
    }

    /**
     * 个人绑卡
     */
    @Override
    public void personalCardBind(PersonalCardBindDto personalCardBindDto) throws PaymentException {
        log.info("YopAdapter#personalCardBind personalCardBindDto={}", JSONUtils.toJSON(personalCardBindDto));

        // 0.参数校验
        personalCardBindDto.checkParam();

        // 1.组装参数
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(personalCardBindDto.getUserId());

        if(thirdUserInfo == null) {
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST);
        }

        WithdrawCardBindRequest requestParam = new WithdrawCardBindRequest();
        requestParam.setMerchantNo(thirdUserInfo.getThirdUserId());
        requestParam.setBankCardType(personalCardBindDto.getCardType());
        requestParam.setAccountNo(personalCardBindDto.getAccount());
        requestParam.setBankCode(personalCardBindDto.getOpenBankCode());
        requestParam.setBranchCode(personalCardBindDto.getBranchBankCd());

        // 2.发送请求
        yopCardBind.cardBind(requestParam);
    }

    /**
     * 解绑卡
     */
    @Override
    public void unBindCard(UnBindCardDto unBindCardDto) throws PaymentException {
        log.info("YopAdapter#unBindCard unBindCardDto={}", JSONUtils.toJSON(unBindCardDto));

        // 1.组装参数
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(unBindCardDto.getUserId());

        if(thirdUserInfo == null) {
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST);
        }

        WithdrawCardModifyRequest requestParam = new WithdrawCardModifyRequest();
        requestParam.setMerchantNo(thirdUserInfo.getThirdUserId());
        requestParam.setBankCardOperateType("CANCELLED");
        requestParam.setAccountNo(unBindCardDto.getAccount());

        // 2.发送请求
        yopCardUnBind.cardUnBind(requestParam);
    }

    /**
     * 查询账户余额
     */
    @Override
    public UserBo queryAccount(QueryAccountDto queryAccountDto) throws PaymentException {
        log.info("YopAdapter#queryAccount queryAccountDto={}", JSONUtils.toJSON(queryAccountDto));


        BigDecimal balance = null;

        if(StringUtils.isNotBlank(queryAccountDto.getBalanceAccountType()) &&
                !Objects.equals(queryAccountDto.getBalanceAccountType(), BalanceAccountTypeEnum.FUND_ACCOUNT.getType()))
        {
            // 1.组装参数
            AccountinfosQueryRequest requestParam = new AccountinfosQueryRequest();
            requestParam.setMerchantNo(queryAccountDto.getThirdUserId());

            // 2.发送请求
            List<AccountinfosQueryAccountDTOResult> results = yopBalanceQueryV2.balanceQueryV2(requestParam);

            for(AccountinfosQueryAccountDTOResult result : results) {
                if(Objects.equals(queryAccountDto.getBalanceAccountType(), result.getAccountType())) {
                    balance = result.getBalance();
                    break;
                }
            }

            if(balance == null) {
                throw new PaymentException(ResultCodeEnum.PARAM_ERROR.getCode(), "未查询到账户信息");
            }
        }
        // 默认查询资金账户余额
        else {
            // 1.组装参数
            BalanceQueryRequest requestParam = new BalanceQueryRequest();
            requestParam.setMerchantNo(queryAccountDto.getThirdUserId());

            // 2.发送请求
            BalanceQueryAccountInfoRespDTOResult result = yopBalanceQuery.balanceQuery(requestParam);
            balance = result.getBalance();
        }

        // 3.构建响应参数
        return UserBo.builder().
                availableBalance(AmountCastUtil.castYuan2FenLong(balance.toString())).
                withdrawableBalance(AmountCastUtil.castYuan2FenLong(balance.toString())).
                build();
    }

    /**
     * 查询交易状态（支付平台内部逻用：退款，转账）
     */
    @Override
    public QueryResultBo queryTransactionStatus(QueryTransactionStatusDto queryTransactionStatusDto) throws PaymentException {
        log.info("YopAdapter#queryTransactionStatus queryTransactionStatusDto={}", JSONUtils.toJSON(queryTransactionStatusDto));

        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(queryTransactionStatusDto.getAccountId());

        if(thirdUserInfo == null) {
            throw new PaymentException(ResultCodeEnum.THIRD_USER_ID_NOT_EXIST);
        }

        if(QueryTransactionStatusDto.TRADE_TYPE_REFUND.equals(queryTransactionStatusDto.getTradeType())) {
            // 组装参数
            RefundQueryRequest requestParam = new RefundQueryRequest();
            RefundOrder refundOrder = refundOrderService.selectByRefundNo(queryTransactionStatusDto.getTransactionNo());
            requestParam.setParentMerchantNo(ApolloUtil.getProperty("yop.merchantNo"));
            requestParam.setMerchantNo(thirdUserInfo.getThirdUserId());
            requestParam.setOrderId(refundOrder.getPayNo());
            requestParam.setRefundRequestId(refundOrder.getRefundNo());

            // 发送请求
            RefundQueryQueryRefundResponseDTOResult result = yopRefundQuery.refundQuery(requestParam);

            if(result == null) {
                return null;
            }

            // 构建响应参数
            return QueryResultBo.build(QueryResultBo.convert(result.getStatus()), DateUtil.strToLong(result.getRefundSuccessDate()),
                    result.getUniqueRefundNo(), AmountCastUtil.castYuan2Fen(result.getRefundAmount().toString()));
        }
        else if(QueryTransactionStatusDto.TRADE_TYPE_TRANSFER.equals(queryTransactionStatusDto.getTradeType())) {
            // 组装参数
            TransferSystemQueryRequest requestParam = new TransferSystemQueryRequest();
            requestParam.setMerchantNo(thirdUserInfo.getThirdUserId());
            requestParam.setRequestNo(queryTransactionStatusDto.getTransactionNo());

            // 发送请求
            TransferSystemQueryMgTransferOrderQueryRespDTOResult result = yopTransferQuery.transferQuery(requestParam);

            if(result == null) {
                return null;
            }

            // 构建响应参数
            return QueryResultBo.build(QueryResultBo.convert(result.getTransferStatus()), DateUtil.strToLong(result.getFinishTime()),
                    result.getOrderNo(), AmountCastUtil.castYuan2Fen(result.getOrderAmount()));
        }

        throw new PaymentException(ResultCodeEnum.UN_SUPPORT_METHOD);
    }

    /**
     * 支付
     */
    @Override
    public PayBo pay(PayDto payDto) throws PaymentException {
        log.info("YopAdapter#pay payDto={}", JSONUtils.toJSON(payDto));
        String key = payDto.getPayNo()+payDto.getChannel();
        if (payDto.getChannel().contains(ChannelEnum.WX.getCode()) && payDto.getMap().get("openId") != null) {
            key = key+(String) payDto.getMap().get("openId");
        } else if(payDto.getChannel().contains(ChannelEnum.ALIPAY.getCode()) && payDto.getMap().get("buyerId") != null) {
            key = key+(String) payDto.getMap().get("buyerId");
        }
        // 0.从缓存中获取
        PayBo redisPayBo = redisUtil.get(key, PayBo.class);

        if(redisPayBo != null) {
            log.info("YopAdapter#pay end get from redis appPayBo:{}", JSON.toJSONString(redisPayBo));
            return redisPayBo;
        }

        // 1.组装参数
        PrePayRequest requestParam = new PrePayRequest();
        requestParam.setParentMerchantNo(ApolloUtil.getProperty("yop.merchantNo"));
        requestParam.setMerchantNo(ApolloUtil.getProperty("yop.merchantNo"));
        requestParam.setOrderId(payDto.getPayNo());
        requestParam.setOrderAmount(AmountCastUtil.castFen2YuanByBigDecimal(payDto.getAmount()));
        requestParam.setMemo(payDto.getBusinessOrderNo());
        FBankPowerIdEnum powerId = FBankPowerIdEnum.getPowerId(payDto.getChannel(), payDto.getPayMode());
        log.info("YopAdapter#pay Channel:{},PayMode:{},{}",payDto.getChannel(), payDto.getPayMode(),JSONObject.toJSONString(powerId));
        if(payDto.getChannel().contains(ChannelEnum.WX.getCode())) {
            Pair appId = FBankPowerIdEnum.getAppIdInfo(payDto.getBusinessOrderType(), powerId);
            requestParam.setChannel(powerId.getYopChannel());
            requestParam.setPayWay(powerId.getYopPayWay());
            requestParam.setAppId(appId.getKey());
            requestParam.setUserId((String) payDto.getMap().get("openId"));
        }
        else if(payDto.getChannel().contains(ChannelEnum.ALIPAY.getCode())) {
            requestParam.setChannel(powerId.getYopChannel());
            requestParam.setPayWay(powerId.getYopPayWay());
            requestParam.setUserId((String) payDto.getMap().get("buyerId"));
        }

        requestParam.setScene("OFFLINE");
        requestParam.setGoodsName(payDto.getSubject());
        String clientIp = (String) payDto.getMap().get("client_ip");

        if(StringUtils.isNotBlank(clientIp)) {
            requestParam.setUserIp(clientIp);
        }
        else {
            requestParam.setUserIp(Constants.DEFAULT_CLIENT_IP);
        }

        // 支付结果回调地址
        requestParam.setNotifyUrl(ApolloUtil.getProperty("yop.callBack.pay"));
        // 清算结果回调地址
        requestParam.setCsUrl(ApolloUtil.getProperty("yop.callBack.clear"));

        // 2.发送请求
        PrePayOrderResponseDTOResult result = yopPay.pay(requestParam);

        // 3.构建响应参数
        PayBo payBo = new PayBo();

        if(payDto.getChannel().contains(ChannelEnum.WX.getCode())) {
            payBo.setPayLoad(WxUtil.convertWXPayLoad(result.getPrePayTn()));
        }
        else if(payDto.getChannel().contains(ChannelEnum.ALIPAY.getCode())) {
            payBo.setPayLoad(result.getPrePayTn());
        }

        payBo.setPayNO(payDto.getPayNo());

        // 4.设置缓存
        redisUtil.set(key, payBo, PayTimeExpireUtil.handleTimeExpire(payDto.getChannel(), payDto.getPayMode(), payDto.getTimeExpire()));
        return payBo;
    }

    /**
     * 退款
     */
    @Override
    public RefundBO refund(RefundDto refundDto) throws PaymentException {
        log.info("YopAdapter#refund refundDto={}", JSONUtils.toJSON(refundDto));

        // 1.组装参数
        RefundRequest requestParam = new RefundRequest();
        requestParam.setParentMerchantNo(ApolloUtil.getProperty("yop.merchantNo"));
        requestParam.setMerchantNo(ApolloUtil.getProperty("yop.merchantNo"));
        requestParam.setOrderId(refundDto.getPayNo());
        requestParam.setRefundRequestId(refundDto.getRefundNo());
        requestParam.setRefundAmount(AmountCastUtil.castFen2Yuan(refundDto.getAmount()));
        requestParam.setDescription(refundDto.getDescription());
        requestParam.setMemo(refundDto.getBusinessOrderNo());
        requestParam.setNotifyUrl(ApolloUtil.getProperty("yop.callBack.refund"));

        // 2.发送请求
        RefundResponseRefundDTOResult result = yopRefund.refund(requestParam);

        // 3.构建响应参数
        RefundBO refundBO = new RefundBO();
        refundBO.setRefundNo(refundDto.getRefundNo());
        refundBO.setChannelRefundNo(result.getUniqueRefundNo());
        refundBO.setStatus(RefundOrder.STATUS_IN);
        return refundBO;
    }

    /**
     * 账户转账
     */
    @Override
    public SeparateAccountsBo separateAccountBetweenUser(SeparateAccountDO separateAccountDO) throws PaymentException {
        log.info("YopAdapter#separateAccountBetweenUser separateAccountDO={}", JSONUtils.toJSON(separateAccountDO));

        // 1.组装参数
        TransferB2bOrderRequest requestParam = new TransferB2bOrderRequest();
        requestParam.setParentMerchantNo(ApolloUtil.getProperty("yop.merchantNo"));
        requestParam.setRequestNo(separateAccountDO.getSeparateNo());
        requestParam.setFromMerchantNo(separateAccountDO.getAccountOut());
        requestParam.setToMerchantNo(separateAccountDO.getAccountIn());
        requestParam.setOrderAmount(AmountCastUtil.castFen2Yuan(separateAccountDO.getTradeAmount()));
        requestParam.setUsage(separateAccountDO.getBusinessOrderNo());

        // 2.发送请求
        TransferB2bOrderMgTransferOrderRespDTOResult result = yopTransfer.transfer(requestParam);

        // 3.构建响应参数
        return SeparateAccountsBo.build(separateAccountDO.getSeparateNo());
    }

    /**
     * 上传图片
     */
    public String uploadPicture(String url, String accountId) throws PaymentException {
        return yopFileUpload.fileUpload(PicUtil.toLocalFile(url, accountId));
    }
}
